home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / TEMPLDEF.PAK / LIST.CTT < prev    next >
Text File  |  1997-05-06  |  18KB  |  648 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // class CList<TYPE, ARG_TYPE> - a list containing 'TYPE' elements
  3. // passed in parameters as ARG_TYPE
  4. //
  5. // optional definitions:
  6. //  IS_SERIAL   - enable serialization through CArchive extraction & insertion
  7. //  HAS_CREATE  - call constructors and destructors
  8. //
  9. // This is a part of the Microsoft Foundation Classes C++ library.
  10. // Copyright (C) 1992 Microsoft Corporation
  11. // All rights reserved.
  12. //
  13. // This source code is only intended as a supplement to the
  14. // Microsoft Foundation Classes Reference and related
  15. // electronic documentation provided with the library.
  16. // See these sources for detailed information regarding the
  17. // Microsoft Foundation Classes product.
  18. /////////////////////////////////////////////////////////////////////////////
  19.  
  20. //$DECLARE_TEMPLATE
  21. /////////////////////////////////////////////////////////////////////////////
  22. template<class TYPE, class ARG_TYPE>
  23. class CList : public CObject
  24. {
  25. $ifdef IS_SERIAL
  26.     DECLARE_SERIAL(CList)
  27. $else
  28.     DECLARE_DYNAMIC(CList)
  29. $endif //!IS_SERIAL
  30.  
  31. protected:
  32.     struct CNode
  33.     {
  34.         CNode* pNext;
  35.         CNode* pPrev;
  36.         TYPE data;
  37.     };
  38. public:
  39.  
  40. // Construction
  41.     CList(int nBlockSize = 10);
  42.  
  43. // Attributes (head and tail)
  44.     // count of elements
  45.     int GetCount() const;
  46.     BOOL IsEmpty() const;
  47.  
  48.     // peek at head or tail
  49.     TYPE& GetHead();
  50.     TYPE GetHead() const;
  51.     TYPE& GetTail();
  52.     TYPE GetTail() const;
  53.  
  54. // Operations
  55.     // get head or tail (and remove it) - don't call on empty list!
  56.     TYPE RemoveHead();
  57.     TYPE RemoveTail();
  58.  
  59.     // add before head or after tail
  60.     POSITION AddHead(ARG_TYPE newElement);
  61.     POSITION AddTail(ARG_TYPE newElement);
  62.  
  63.     // add another list of elements before head or after tail
  64.     void AddHead(CList* pNewList);
  65.     void AddTail(CList* pNewList);
  66.  
  67.     // remove all elements
  68.     void RemoveAll();
  69.  
  70.     // iteration
  71.     POSITION GetHeadPosition() const;
  72.     POSITION GetTailPosition() const;
  73.     TYPE& GetNext(POSITION& rPosition); // return *Position++
  74.     TYPE GetNext(POSITION& rPosition) const; // return *Position++
  75.     TYPE& GetPrev(POSITION& rPosition); // return *Position--
  76.     TYPE GetPrev(POSITION& rPosition) const; // return *Position--
  77.  
  78.     // getting/modifying an element at a given position
  79.     TYPE& GetAt(POSITION position);
  80.     TYPE GetAt(POSITION position) const;
  81.     void SetAt(POSITION pos, ARG_TYPE newElement);
  82.     void RemoveAt(POSITION position);
  83.  
  84.     // inserting before or after a given position
  85.     POSITION InsertBefore(POSITION position, ARG_TYPE newElement);
  86.     POSITION InsertAfter(POSITION position, ARG_TYPE newElement);
  87.  
  88.     // helper functions (note: O(n) speed)
  89.     POSITION Find(ARG_TYPE searchValue, POSITION startAfter = NULL) const;
  90.                         // defaults to starting at the HEAD
  91.                         // return NULL if not found
  92.     POSITION FindIndex(int nIndex) const;
  93.                         // get the 'nIndex'th element (may return NULL)
  94.  
  95. // Implementation
  96. protected:
  97.     CNode* m_pNodeHead;
  98.     CNode* m_pNodeTail;
  99.     int m_nCount;
  100.     CNode* m_pNodeFree;
  101.     struct CPlex* m_pBlocks;
  102.     int m_nBlockSize;
  103.  
  104.     CNode* NewNode(CNode*, CNode*);
  105.     void FreeNode(CNode*);
  106.  
  107. public:
  108.     ~CList();
  109. $ifdef IS_SERIAL
  110.     void Serialize(CArchive&);
  111. $endif //IS_SERIAL
  112. #ifdef _DEBUG
  113.     void Dump(CDumpContext&) const;
  114.     void AssertValid() const;
  115. #endif
  116.     // local typedefs for class templates
  117.     typedef TYPE BASE_TYPE;
  118.     typedef ARG_TYPE BASE_ARG_TYPE;
  119. };
  120.  
  121. //$IMPLEMENT_TEMPLATE_INLINES
  122. ////////////////////////////////////////////////////////////////////////////
  123.  
  124. template<class TYPE, class ARG_TYPE>
  125. _AFXCOLL_INLINE int CList<TYPE, ARG_TYPE>::GetCount() const
  126.     { return m_nCount; }
  127. template<class TYPE, class ARG_TYPE>
  128. _AFXCOLL_INLINE BOOL CList<TYPE, ARG_TYPE>::IsEmpty() const
  129.     { return m_nCount == 0; }
  130. template<class TYPE, class ARG_TYPE>
  131. _AFXCOLL_INLINE TYPE& CList<TYPE, ARG_TYPE>::GetHead()
  132.     { ASSERT(m_pNodeHead != NULL);
  133.         return m_pNodeHead->data; }
  134. template<class TYPE, class ARG_TYPE>
  135. _AFXCOLL_INLINE TYPE CList<TYPE, ARG_TYPE>::GetHead() const
  136.     { ASSERT(m_pNodeHead != NULL);
  137.         return m_pNodeHead->data; }
  138. template<class TYPE, class ARG_TYPE>
  139. _AFXCOLL_INLINE TYPE& CList<TYPE, ARG_TYPE>::GetTail()
  140.     { ASSERT(m_pNodeTail != NULL);
  141.         return m_pNodeTail->data; }
  142. template<class TYPE, class ARG_TYPE>
  143. _AFXCOLL_INLINE TYPE CList<TYPE, ARG_TYPE>::GetTail() const
  144.     { ASSERT(m_pNodeTail != NULL);
  145.         return m_pNodeTail->data; }
  146. template<class TYPE, class ARG_TYPE>
  147. _AFXCOLL_INLINE POSITION CList<TYPE, ARG_TYPE>::GetHeadPosition() const
  148.     { return (POSITION) m_pNodeHead; }
  149. template<class TYPE, class ARG_TYPE>
  150. _AFXCOLL_INLINE POSITION CList<TYPE, ARG_TYPE>::GetTailPosition() const
  151.     { return (POSITION) m_pNodeTail; }
  152. template<class TYPE, class ARG_TYPE>
  153. _AFXCOLL_INLINE TYPE& CList<TYPE, ARG_TYPE>::GetNext(POSITION& rPosition) // return *Position++
  154.     { CNode* pNode = (CNode*) rPosition;
  155.         ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  156.         rPosition = (POSITION) pNode->pNext;
  157.         return pNode->data; }
  158. template<class TYPE, class ARG_TYPE>
  159. _AFXCOLL_INLINE TYPE CList<TYPE, ARG_TYPE>::GetNext(POSITION& rPosition) const // return *Position++
  160.     { CNode* pNode = (CNode*) rPosition;
  161.         ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  162.         rPosition = (POSITION) pNode->pNext;
  163.         return pNode->data; }
  164. template<class TYPE, class ARG_TYPE>
  165. _AFXCOLL_INLINE TYPE& CList<TYPE, ARG_TYPE>::GetPrev(POSITION& rPosition) // return *Position--
  166.     { CNode* pNode = (CNode*) rPosition;
  167.         ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  168.         rPosition = (POSITION) pNode->pPrev;
  169.         return pNode->data; }
  170. template<class TYPE, class ARG_TYPE>
  171. _AFXCOLL_INLINE TYPE CList<TYPE, ARG_TYPE>::GetPrev(POSITION& rPosition) const // return *Position--
  172.     { CNode* pNode = (CNode*) rPosition;
  173.         ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  174.         rPosition = (POSITION) pNode->pPrev;
  175.         return pNode->data; }
  176. template<class TYPE, class ARG_TYPE>
  177. _AFXCOLL_INLINE TYPE& CList<TYPE, ARG_TYPE>::GetAt(POSITION position)
  178.     { CNode* pNode = (CNode*) position;
  179.         ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  180.         return pNode->data; }
  181. template<class TYPE, class ARG_TYPE>
  182. _AFXCOLL_INLINE TYPE CList<TYPE, ARG_TYPE>::GetAt(POSITION position) const
  183.     { CNode* pNode = (CNode*) position;
  184.         ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  185.         return pNode->data; }
  186. template<class TYPE, class ARG_TYPE>
  187. _AFXCOLL_INLINE void CList<TYPE, ARG_TYPE>::SetAt(POSITION pos, ARG_TYPE newElement)
  188.     { CNode* pNode = (CNode*) pos;
  189.         ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  190.         pNode->data = newElement; }
  191.  
  192. //$IMPLEMENT_TEMPLATE
  193. // This is a part of the Microsoft Foundation Classes C++ library.
  194. // Copyright (C) 1992-1995 Microsoft Corporation
  195. // All rights reserved.
  196. //
  197. // This source code is only intended as a supplement to the
  198. // Microsoft Foundation Classes Reference and related
  199. // electronic documentation provided with the library.
  200. // See these sources for detailed information regarding the
  201. // Microsoft Foundation Classes product.
  202.  
  203. /////////////////////////////////////////////////////////////////////////////
  204. //
  205. // Implementation of parameterized List
  206. //
  207. /////////////////////////////////////////////////////////////////////////////
  208.  
  209. #include "stdafx.h"
  210.  
  211. #ifdef AFX_COLL_SEG
  212. #pragma code_seg(AFX_COLL_SEG)
  213. #endif
  214.  
  215. #ifdef _DEBUG
  216. #undef THIS_FILE
  217. static char THIS_FILE[] = __FILE__;
  218. #endif
  219.  
  220. $ifdef HAS_CREATE
  221. #include "elements.h"  // used for special creation
  222. $endif
  223.  
  224. #define new DEBUG_NEW
  225.  
  226. /////////////////////////////////////////////////////////////////////////////
  227.  
  228. template<class TYPE, class ARG_TYPE>
  229. CList<TYPE, ARG_TYPE>::CList(int nBlockSize)
  230. {
  231.     ASSERT(nBlockSize > 0);
  232.  
  233.     m_nCount = 0;
  234.     m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL;
  235.     m_pBlocks = NULL;
  236.     m_nBlockSize = nBlockSize;
  237. }
  238.  
  239. template<class TYPE, class ARG_TYPE>
  240. void CList<TYPE, ARG_TYPE>::RemoveAll()
  241. {
  242.     ASSERT_VALID(this);
  243.  
  244.     // destroy elements
  245. $ifdef HAS_CREATE
  246.     CNode* pNode;
  247.     for (pNode = m_pNodeHead; pNode != NULL; pNode = pNode->pNext)
  248.         DestructElement(&pNode->data);
  249. $endif
  250.  
  251.     m_nCount = 0;
  252.     m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL;
  253.     m_pBlocks->FreeDataChain();
  254.     m_pBlocks = NULL;
  255. }
  256.  
  257. template<class TYPE, class ARG_TYPE>
  258. CList<TYPE, ARG_TYPE>::~CList()
  259. {
  260.     RemoveAll();
  261.     ASSERT(m_nCount == 0);
  262. }
  263.  
  264. /////////////////////////////////////////////////////////////////////////////
  265. // Node helpers
  266. /*
  267.  * Implementation note: CNode's are stored in CPlex blocks and
  268.  *  chained together. Free blocks are maintained in a singly linked list
  269.  *  using the 'pNext' member of CNode with 'm_pNodeFree' as the head.
  270.  *  Used blocks are maintained in a doubly linked list using both 'pNext'
  271.  *  and 'pPrev' as links and 'm_pNodeHead' and 'm_pNodeTail'
  272.  *   as the head/tail.
  273.  *
  274.  * We never free a CPlex block unless the List is destroyed or RemoveAll()
  275.  *  is used - so the total number of CPlex blocks may grow large depending
  276.  *  on the maximum past size of the list.
  277.  */
  278.  
  279. template<class TYPE, class ARG_TYPE>
  280. CList<TYPE, ARG_TYPE>::CNode*
  281. CList<TYPE, ARG_TYPE>::NewNode(CList::CNode* pPrev, CList::CNode* pNext)
  282. {
  283.     if (m_pNodeFree == NULL)
  284.     {
  285.         // add another block
  286.         CPlex* pNewBlock = CPlex::Create(m_pBlocks, m_nBlockSize,
  287.                  sizeof(CNode));
  288.  
  289.         // chain them into free list
  290.         CNode* pNode = (CNode*) pNewBlock->data();
  291.         // free in reverse order to make it easier to debug
  292.         pNode += m_nBlockSize - 1;
  293.         for (int i = m_nBlockSize-1; i >= 0; i--, pNode--)
  294.         {
  295.             pNode->pNext = m_pNodeFree;
  296.             m_pNodeFree = pNode;
  297.         }
  298.     }
  299.     ASSERT(m_pNodeFree != NULL);  // we must have something
  300.  
  301.     CList::CNode* pNode = m_pNodeFree;
  302.     m_pNodeFree = m_pNodeFree->pNext;
  303.     pNode->pPrev = pPrev;
  304.     pNode->pNext = pNext;
  305.     m_nCount++;
  306.     ASSERT(m_nCount > 0);  // make sure we don't overflow
  307.  
  308. $ifdef HAS_CREATE
  309.     ConstructElement(&pNode->data);
  310. $endif
  311. $ifdef USE_MEMSET
  312.     memset(&pNode->data, 0, sizeof(TYPE));  // zero fill
  313. $endif
  314. $ifdef USE_ASSIGN
  315.     pNode->data = 0; // start with zero
  316. $endif
  317.     return pNode;
  318. }
  319.  
  320. template<class TYPE, class ARG_TYPE>
  321. void CList<TYPE, ARG_TYPE>::FreeNode(CList::CNode* pNode)
  322. {
  323. $ifdef HAS_CREATE
  324.     DestructElement(&pNode->data);
  325. $endif
  326.     pNode->pNext = m_pNodeFree;
  327.     m_pNodeFree = pNode;
  328.     m_nCount--;
  329.     ASSERT(m_nCount >= 0);    // make sure we don't underflow
  330.  
  331.     // if no more elements, cleanup completely
  332.     if (m_nCount == 0)
  333.         RemoveAll();
  334. }
  335.  
  336. /////////////////////////////////////////////////////////////////////////////
  337.  
  338. template<class TYPE, class ARG_TYPE>
  339. POSITION CList<TYPE, ARG_TYPE>::AddHead(ARG_TYPE newElement)
  340. {
  341.     ASSERT_VALID(this);
  342.  
  343.     CNode* pNewNode = NewNode(NULL, m_pNodeHead);
  344.     pNewNode->data = newElement;
  345.     if (m_pNodeHead != NULL)
  346.         m_pNodeHead->pPrev = pNewNode;
  347.     else
  348.         m_pNodeTail = pNewNode;
  349.     m_pNodeHead = pNewNode;
  350.     return (POSITION) pNewNode;
  351. }
  352.  
  353. template<class TYPE, class ARG_TYPE>
  354. POSITION CList<TYPE, ARG_TYPE>::AddTail(ARG_TYPE newElement)
  355. {
  356.     ASSERT_VALID(this);
  357.  
  358.     CNode* pNewNode = NewNode(m_pNodeTail, NULL);
  359.     pNewNode->data = newElement;
  360.     if (m_pNodeTail != NULL)
  361.         m_pNodeTail->pNext = pNewNode;
  362.     else
  363.         m_pNodeHead = pNewNode;
  364.     m_pNodeTail = pNewNode;
  365.     return (POSITION) pNewNode;
  366. }
  367.  
  368. template<class TYPE, class ARG_TYPE>
  369. void CList<TYPE, ARG_TYPE>::AddHead(CList* pNewList)
  370. {
  371.     ASSERT_VALID(this);
  372.  
  373.     ASSERT(pNewList != NULL);
  374.     ASSERT_KINDOF(CList, pNewList);
  375.     ASSERT_VALID(pNewList);
  376.  
  377.     // add a list of same elements to head (maintain order)
  378.     POSITION pos = pNewList->GetTailPosition();
  379.     while (pos != NULL)
  380.         AddHead(pNewList->GetPrev(pos));
  381. }
  382.  
  383. template<class TYPE, class ARG_TYPE>
  384. void CList<TYPE, ARG_TYPE>::AddTail(CList* pNewList)
  385. {
  386.     ASSERT_VALID(this);
  387.     ASSERT(pNewList != NULL);
  388.     ASSERT_KINDOF(CList, pNewList);
  389.     ASSERT_VALID(pNewList);
  390.  
  391.     // add a list of same elements
  392.     POSITION pos = pNewList->GetHeadPosition();
  393.     while (pos != NULL)
  394.         AddTail(pNewList->GetNext(pos));
  395. }
  396.  
  397. template<class TYPE, class ARG_TYPE>
  398. TYPE CList<TYPE, ARG_TYPE>::RemoveHead()
  399. {
  400.     ASSERT_VALID(this);
  401.     ASSERT(m_pNodeHead != NULL);  // don't call on empty list !!!
  402.     ASSERT(AfxIsValidAddress(m_pNodeHead, sizeof(CNode)));
  403.  
  404.     CNode* pOldNode = m_pNodeHead;
  405.     TYPE returnValue = pOldNode->data;
  406.  
  407.     m_pNodeHead = pOldNode->pNext;
  408.     if (m_pNodeHead != NULL)
  409.         m_pNodeHead->pPrev = NULL;
  410.     else
  411.         m_pNodeTail = NULL;
  412.     FreeNode(pOldNode);
  413.     return returnValue;
  414. }
  415.  
  416. template<class TYPE, class ARG_TYPE>
  417. TYPE CList<TYPE, class ARG_TYPE>::RemoveTail()
  418. {
  419.     ASSERT_VALID(this);
  420.     ASSERT(m_pNodeTail != NULL);  // don't call on empty list !!!
  421.     ASSERT(AfxIsValidAddress(m_pNodeTail, sizeof(CNode)));
  422.  
  423.     CNode* pOldNode = m_pNodeTail;
  424.     TYPE returnValue = pOldNode->data;
  425.  
  426.     m_pNodeTail = pOldNode->pPrev;
  427.     if (m_pNodeTail != NULL)
  428.         m_pNodeTail->pNext = NULL;
  429.     else
  430.         m_pNodeHead = NULL;
  431.     FreeNode(pOldNode);
  432.     return returnValue;
  433. }
  434.  
  435. template<class TYPE, class ARG_TYPE>
  436. POSITION CList<TYPE>::InsertBefore(POSITION position, ARG_TYPE newElement)
  437. {
  438.     ASSERT_VALID(this);
  439.  
  440.     if (position == NULL)
  441.         return AddHead(newElement); // insert before nothing -> head of the list
  442.  
  443.     // Insert it before position
  444.     CNode* pOldNode = (CNode*) position;
  445.     CNode* pNewNode = NewNode(pOldNode->pPrev, pOldNode);
  446.     pNewNode->data = newElement;
  447.  
  448.     if (pOldNode->pPrev != NULL)
  449.     {
  450.         ASSERT(AfxIsValidAddress(pOldNode->pPrev, sizeof(CNode)));
  451.         pOldNode->pPrev->pNext = pNewNode;
  452.     }
  453.     else
  454.     {
  455.         ASSERT(pOldNode == m_pNodeHead);
  456.         m_pNodeHead = pNewNode;
  457.     }
  458.     pOldNode->pPrev = pNewNode;
  459.     return (POSITION) pNewNode;
  460. }
  461.  
  462. template<class TYPE, class ARG_TYPE>
  463. POSITION CList<TYPE, ARG_TYPE>::InsertAfter(POSITION position, ARG_TYPE newElement)
  464. {
  465.     ASSERT_VALID(this);
  466.  
  467.     if (position == NULL)
  468.         return AddTail(newElement); // insert after nothing -> tail of the list
  469.  
  470.     // Insert it before position
  471.     CNode* pOldNode = (CNode*) position;
  472.     ASSERT(AfxIsValidAddress(pOldNode, sizeof(CNode)));
  473.     CNode* pNewNode = NewNode(pOldNode, pOldNode->pNext);
  474.     pNewNode->data = newElement;
  475.  
  476.     if (pOldNode->pNext != NULL)
  477.     {
  478.         ASSERT(AfxIsValidAddress(pOldNode->pNext, sizeof(CNode)));
  479.         pOldNode->pNext->pPrev = pNewNode;
  480.     }
  481.     else
  482.     {
  483.         ASSERT(pOldNode == m_pNodeTail);
  484.         m_pNodeTail = pNewNode;
  485.     }
  486.     pOldNode->pNext = pNewNode;
  487.     return (POSITION) pNewNode;
  488. }
  489.  
  490. template<class TYPE, class ARG_TYPE>
  491. void CList<TYPE, ARG_TYPE>::RemoveAt(POSITION position)
  492. {
  493.     ASSERT_VALID(this);
  494.  
  495.     CNode* pOldNode = (CNode*) position;
  496.     ASSERT(AfxIsValidAddress(pOldNode, sizeof(CNode)));
  497.  
  498.     // remove pOldNode from list
  499.     if (pOldNode == m_pNodeHead)
  500.     {
  501.         m_pNodeHead = pOldNode->pNext;
  502.     }
  503.     else
  504.     {
  505.         ASSERT(AfxIsValidAddress(pOldNode->pPrev, sizeof(CNode)));
  506.         pOldNode->pPrev->pNext = pOldNode->pNext;
  507.     }
  508.     if (pOldNode == m_pNodeTail)
  509.     {
  510.         m_pNodeTail = pOldNode->pPrev;
  511.     }
  512.     else
  513.     {
  514.         ASSERT(AfxIsValidAddress(pOldNode->pNext, sizeof(CNode)));
  515.         pOldNode->pNext->pPrev = pOldNode->pPrev;
  516.     }
  517.     FreeNode(pOldNode);
  518. }
  519.  
  520.  
  521. /////////////////////////////////////////////////////////////////////////////
  522. // slow operations
  523.  
  524. template<class TYPE, class ARG_TYPE>
  525. POSITION CList<TYPE, ARG_TYPE>::FindIndex(int nIndex) const
  526. {
  527.     ASSERT_VALID(this);
  528.     ASSERT(nIndex >= 0);
  529.  
  530.     if (nIndex >= m_nCount)
  531.         return NULL;  // went too far
  532.  
  533.     CNode* pNode = m_pNodeHead;
  534.     while (nIndex--)
  535.     {
  536.         ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  537.         pNode = pNode->pNext;
  538.     }
  539.     return (POSITION) pNode;
  540. }
  541.  
  542. template<class TYPE, class ARG_TYPE>
  543. POSITION CList<TYPE, ARG_TYPE>::Find(ARG_TYPE searchValue, POSITION startAfter) const
  544. {
  545.     ASSERT_VALID(this);
  546.  
  547.     CNode* pNode = (CNode*) startAfter;
  548.     if (pNode == NULL)
  549.     {
  550.         pNode = m_pNodeHead;  // start at head
  551.     }
  552.     else
  553.     {
  554.         ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  555.         pNode = pNode->pNext;  // start after the one specified
  556.     }
  557.  
  558.     for (; pNode != NULL; pNode = pNode->pNext)
  559.         if (pNode->data == searchValue)
  560.             return (POSITION) pNode;
  561.     return NULL;
  562. }
  563.  
  564. $ifdef IS_SERIAL
  565. /////////////////////////////////////////////////////////////////////////////
  566. // Serialization
  567.  
  568. template<class TYPE, class ARG_TYPE>
  569. void CList<TYPE, ARG_TYPE>::Serialize(CArchive& ar)
  570. {
  571.     ASSERT_VALID(this);
  572.  
  573.     CObject::Serialize(ar);
  574.  
  575.     if (ar.IsStoring())
  576.     {
  577.         ar.WriteCount(m_nCount);
  578.         for (CNode* pNode = m_pNodeHead; pNode != NULL; pNode = pNode->pNext)
  579.         {
  580.             ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  581.             ar << pNode->data;
  582.         }
  583.     }
  584.     else
  585.     {
  586.         DWORD nNewCount = ar.ReadCount();
  587.         TYPE newData;
  588.         while (nNewCount--)
  589.         {
  590.             ar >> newData;
  591.             AddTail(newData);
  592.         }
  593.     }
  594. }
  595. $endif //IS_SERIAL
  596.  
  597. /////////////////////////////////////////////////////////////////////////////
  598. // Diagnostics
  599.  
  600. #ifdef _DEBUG
  601. template<class TYPE, class ARG_TYPE>
  602. void CList<TYPE, ARG_TYPE>::Dump(CDumpContext& dc) const
  603. {
  604.     CObject::Dump(dc);
  605.  
  606.     dc << "with " << m_nCount << " elements";
  607.     if (dc.GetDepth() > 0)
  608.     {
  609.         POSITION pos = GetHeadPosition();
  610.         while (pos != NULL)
  611.             dc << "\n\t" << GetNext(pos);
  612.     }
  613.  
  614.     dc << "\n";
  615. }
  616.  
  617. template<class TYPE, class ARG_TYPE>
  618. void CList<TYPE, ARG_TYPE>::AssertValid() const
  619. {
  620.     CObject::AssertValid();
  621.  
  622.     if (m_nCount == 0)
  623.     {
  624.         // empty list
  625.         ASSERT(m_pNodeHead == NULL);
  626.         ASSERT(m_pNodeTail == NULL);
  627.     }
  628.     else
  629.     {
  630.         // non-empty list
  631.         ASSERT(AfxIsValidAddress(m_pNodeHead, sizeof(CNode)));
  632.         ASSERT(AfxIsValidAddress(m_pNodeTail, sizeof(CNode)));
  633.     }
  634. }
  635. #endif //_DEBUG
  636.  
  637. #ifdef AFX_INIT_SEG
  638. #pragma code_seg(AFX_INIT_SEG)
  639. #endif
  640.  
  641. $ifdef IS_SERIAL
  642. IMPLEMENT_SERIAL(CList, CObject, 0)
  643. $else
  644. IMPLEMENT_DYNAMIC(CList, CObject)
  645. $endif //!IS_SERIAL
  646.  
  647. /////////////////////////////////////////////////////////////////////////////
  648.